package cn.getech.data.development.utils;


import cn.getech.data.development.dto.FileModelDto;
import cn.getech.data.intelligence.common.exception.RRException;
import cn.getech.data.intelligence.common.utils.FileUtils;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 生成压缩文件 （zip，rar 格式）
 */
public class CompressUtil {

    private static Logger log = LoggerFactory.getLogger(CompressUtil.class);


    public static boolean createJSONFile(Object obj, Long versionId) {
        boolean flag = true;
        try {
            //获取文件的绝对路径根路径
//            String filePath = ResourceUtils.getURL("classpath:").getPath();
            String jsonString = JSONObject.toJSONString(obj);

            // 拼接文件完整路径// 生成json格式文件
            String fullPath = "./" + versionId + ".json";

            // 保证创建一个新文件
            File file = new File(fullPath);
            // 如果父目录不存在，创建父目录
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            // 如果已存在,删除旧文件
            if (file.exists()) {
                file.delete();
            }
            //创建新文件
            file.createNewFile();

            if (jsonString.indexOf("'") != -1) {
                //将单引号转义一下，因为JSON串中的字符串类型可以单引号引起来的
                jsonString = jsonString.replaceAll("'", "\\'");
            }
            if (jsonString.indexOf("\"") != -1) {
                //将双引号转义一下，因为JSON串中的字符串类型可以单引号引起来的
                jsonString = jsonString.replaceAll("\"", "\\\"");
            }

            if (jsonString.indexOf("\r\n") != -1) {
                //将回车换行转换一下，因为JSON串中字符串不能出现显式的回车换行
                jsonString = jsonString.replaceAll("\r\n", "\\u000d\\u000a");
            }
            if (jsonString.indexOf("\n") != -1) {
                //将换行转换一下，因为JSON串中字符串不能出现显式的换行
                jsonString = jsonString.replaceAll("\n", "\\u000a");
            }
            // 将格式化后的字符串写入文件
            Writer write = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            write.write(jsonString);
            write.flush();
            write.close();
        } catch (Exception e) {
            flag = false;
            e.printStackTrace();
        }
        return flag;
    }


    //读取json文件
    public static String readJsonFile(InputStream inputStream) {
        try {
            Reader reader = new InputStreamReader(inputStream, "utf-8");
            int ch = 0;
            StringBuffer sb = new StringBuffer();
            while ((ch = reader.read()) != -1) {
                sb.append((char) ch);
            }
            inputStream.close();
            reader.close();
            return sb.toString();
        } catch (IOException e) {
            log.error("解析json文件异常！error:{}", e.getMessage());
            return null;
        }
    }


    /**
     * 设置下载响应头
     *
     * @param response
     * @param request
     * @return
     */
    public static HttpServletResponse setDownloadResponse(HttpServletResponse response, String downloadName, HttpServletRequest request) throws UnsupportedEncodingException {
        response.reset();
        response.setHeader("Content-Type", "application/octet-stream");
        String fileName = String.format("%s", URLEncoder.encode(downloadName, "utf-8"));
//        try {
//            fileName = filenameEncoding(downloadName, request);
//        } catch (IOException e) {
//            log.error("编码文件名异常！error:{}",e.getMessage());
//        }
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        response.setHeader("filename", fileName);
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.setCharacterEncoding("UTF-8");
        return response;
    }

    public static String filenameEncoding(String filename, HttpServletRequest request) throws IOException {
        //获取浏览器
        String agent = request.getHeader("User-Agent");
        if (agent.contains("Firefox")) {
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?utf-8?B?"
                    + base64Encoder.encode(filename.getBytes("utf-8"))
                    + "?=";
        } else if (agent.contains("MSIE")) {
            filename = URLEncoder.encode(filename, "utf-8");
        } else if (agent.contains("Safari")) {
            filename = new String(filename.getBytes("utf-8"), "ISO8859-1");
        } else {
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }

    /**
     * 将多个文件压缩到指定输出流中
     *
     * @param files        需要压缩的文件列表
     * @param outputStream 压缩到指定的输出流
     */
    public static void compressZip(List<File> files, OutputStream outputStream) {
        ZipOutputStream zipOutStream = null;
        try {
            //-- 包装成ZIP格式输出流
            zipOutStream = new ZipOutputStream(new BufferedOutputStream(outputStream));
            // -- 设置压缩方法
            zipOutStream.setMethod(ZipOutputStream.DEFLATED);
            //-- 将多文件循环写入压缩包
            for (int i = 0; i < files.size(); i++) {
                File file = files.get(i);
                FileInputStream filenputStream = new FileInputStream(file);
                byte[] data = new byte[(int) file.length()];
                filenputStream.read(data);
                //-- 添加ZipEntry，并ZipEntry中写入文件流，这里，加上i是防止要下载的文件有重名的导致下载失败
                zipOutStream.putNextEntry(new ZipEntry(i + file.getName()));
                zipOutStream.write(data);
                filenputStream.close();
                zipOutStream.closeEntry();
            }
        } catch (IOException e) {
            log.error("downloadallfiles:error:{}", e.getMessage());
        } finally {
            try {
                if (Objects.nonNull(zipOutStream)) {
                    zipOutStream.flush();
                    zipOutStream.close();
                }
                if (Objects.nonNull(outputStream)) {
                    outputStream.close();
                }
            } catch (IOException e) {
                log.error("downloadallfiles:error:{}", e.getMessage());
            }
        }
    }

    /**
     * 下载文件
     *
     * @param outputStream 下载输出流
     * @param zipFilePath  需要下载文件的路径
     */
    public static void downloadFile(OutputStream outputStream, String zipFilePath) {
        File zipFile = new File(zipFilePath);
        if (!zipFile.exists()) {
            //-- 需要下载压塑包文件不存在
            return;
        }
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(zipFile);
            byte[] data = new byte[(int) zipFile.length()];
            inputStream.read(data);
            outputStream.write(data);
            outputStream.flush();
        } catch (IOException e) {
            log.error("downloadZip:error:{}", e.getMessage());
        } finally {
            try {
                if (Objects.nonNull(inputStream)) {
                    inputStream.close();
                }
                if (Objects.nonNull(outputStream)) {
                    outputStream.close();
                }
            } catch (IOException e) {
                log.error("downloadZip:error:{}", e.getMessage());
            }
        }
    }

    /**
     * 删除指定路径的文件
     *
     * @param filepath
     */
    public static void deleteFile(String filepath) {
        File file = new File(filepath);
        deleteFile(file);
    }

    /**
     * 删除指定文件
     *
     * @param file
     */
    public static void deleteFile(File file) {
        //-- 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
        }
    }


    /**
     * 对zip类型的文件进行解压
     */
    public static List<FileModelDto> unzip(MultipartFile file) {
        // 判断文件是否为zip文件
        String filename = file.getOriginalFilename();

        if (!filename.endsWith("zip")) {
            log.info("传入文件格式不是zip文件" + filename);
            new RRException("传入文件格式错误" + filename);
        }
        List<FileModelDto> fileModelList = new ArrayList<>();
        String zipFileName = null;
        ZipInputStream zipInputStream = null;
        // 对文件进行解析
        try {
            File changeFile = FileUtils.multipartFileToFile(file);
            ZipFile zf = new ZipFile(changeFile);
            zipInputStream = new ZipInputStream(file.getInputStream(), Charset.forName("utf-8"));
            ZipEntry zipEntry;
            // 获取zip包中的每一个zip file entry
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                zipFileName = zipEntry.getName();
                Assert.notNull(zipFileName, "压缩文件中子文件的名字格式不正确");
                FileModelDto fileModel = new FileModelDto();
                fileModel.setFileName(zipFileName);
                InputStream inputStream = zf.getInputStream(zipEntry);
                fileModel.setFileInputstream(inputStream);
                fileModelList.add(fileModel);
            }
        } catch (Exception e) {
            log.error("读取部署包文件内容失败,请确认部署包格式正确:" + zipFileName, e);
            new RRException("读取部署包文件内容失败,请确认部署包格式正确:" + zipFileName);
        } finally {
            if(null != zipInputStream){
                try {
                    zipInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return fileModelList;
    }


    //输入流转成byte数组
    public static byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        return output.toByteArray();
    }

}
